<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) https://inphp.cc All rights reserved.
// | 该文件源码由INPHP官方提供，使用协议以INPHP官方公告为准。
// +----------------------------------------------------------------------
// | 支付处理
// +----------------------------------------------------------------------
namespace app\finance\onlinePay\alipay;

use app\cms\tags\category;
use app\finance\model\CashierModel;
use app\finance\onlinePay\IPay;
use Inphp\Core\Object\Message;
use Inphp\Core\Services\Http\Response;
use Inphp\Core\Util\Log;

class pay implements IPay
{
    /**
     * 创建订单
     * @param array $arg
     * @return Message
     */
    public function prepay(array $arg = []): Message
    {
        // TODO: Implement prepay() method.
        //支付金额
        $amount = $arg["amount"] ?? 0;
        $amount = is_numeric($amount) && $amount > 0 ? $amount : 0;
        if ($amount <= 0) {
            return httpMessage("支付金额必须大于0");
        }
        //收银单ID
        $cashierId = $arg["cashierId"] ?? 0;
        if (empty($cashierId)) {
            return httpMessage("缺少收银单号");
        }
        //支付参数
        $params = $arg["params"] ?? [];
        if (empty($params)) {
            //return httpMessage("缺少支付参数");
        }
        //可能是客户端自定义APP ID
        $appId = $params["appId"] ?? null;
        //取配置
        $payments = CashierModel::onlinePayments();
        $config = $payments["alipay"] ?? null;
        if (empty($config)) {
            return httpMessage("缺少配置参数");
        }
        if (!$config["enable"]) {
            return httpMessage("该支付方式暂未开放");
        }
        $appList = $config["appList"] ?? [];
        if (empty($appList)) {
            return httpMessage("没有可用的支付应用");
        }
        $app = !empty($appId) ? ($appList[$appId] ?? reset($appList)) : reset($appList);
        $app = is_array($app) ? $app : [];
        if (empty($app)) {
            return httpMessage("未配置的支付应用");
        }
        $appId = $app["appId"] ?? $appId;
        if (empty($appId)) {
            return httpMessage("缺少支付应用ID");
        }
        //开发模式
        $dev = isset($app["dev"]) && $app["dev"] === true;
        //如果是开发模式，将把支付金额改为0.01元
        $amount = $dev ? 0.01 : $amount;
        //域名地址
        $host = getHost();
        //异步通知地址
        $notifyUrl = $host."/finance/pay/notify/alipay_{$appId}";
        $notifyUrl = $app["notifyUrl"] ?? $notifyUrl;
        //同步地址
        $redirectUrl = $host."/finance/pay/callback/alipay_{$appId}";
        $redirectUrl = $app["redirectUrl"] ?? $redirectUrl;
        //订单号前缀
        $outTradeNoPrefix = $app["outTradeNoPrefix"] ?? "";
        //生成单号
        $outTradeNo = $outTradeNoPrefix.$cashierId;
        //统一网关
        $gatewayUrl = $app["gatewayUrl"] ?? "https://openapi.alipay.com/gateway.do";
        //构造
        $alipayParams = new \Yurun\PaySDK\AlipayApp\Params\PublicParams;
        $alipayParams->appID = $appId;
        $alipayParams->appPrivateKey = $app["privateKey"];
        $alipayParams->appPublicKey = $app["publicKey"];
        $alipayParams->apiDomain = $gatewayUrl;
        //
        $sdk = new \Yurun\PaySDK\AlipayApp\SDK($alipayParams);
        $sdkRequest = new \Yurun\PaySDK\AlipayApp\Wap\Params\Pay\Request;
        $sdkRequest->notify_url = $notifyUrl;
        $sdkRequest->return_url = $redirectUrl;
        $sdkRequest->businessParams = new \Yurun\PaySDK\AlipayApp\Wap\Params\Pay\BusinessParams;
        //交易单号
        $sdkRequest->businessParams->out_trade_no = $outTradeNo;
        //支付金额
        $sdkRequest->businessParams->total_amount = $amount;
        //商品说明
        $description = $arg["subject"] ?? "";
        $description .= $arg["info"] ?? "";
        $sdkRequest->businessParams->subject = $description;
        //执行
        $sdk->prepareExecute($sdkRequest, $redirectUrl, $data);
        if (!empty($redirectUrl) && is_string($redirectUrl) && stripos($redirectUrl, "https://") === 0) {
            return httpMessage(0, "success", [
                "payed"         => 0,
                "redirectUrl"   => $redirectUrl,
                "data"          => $data
            ]);
        }
        return httpMessage("未能取得支付地址");
    }

    /**
     * 同步回调
     * @param string|null $appId
     * @return mixed
     */
    public function callback(?string $appId = null): mixed
    {
        // TODO: Implement callback() method.
        return \redirect("/");
    }

    public function notify(?string $appId = null)
    {
        // TODO: Implement notify() method.
        //取配置
        $payments = CashierModel::payments();
        $config = $payments["wechat"] ?? null;
        if (empty($config)) {
            getHttpResponse()->withText("Fail: 缺少配置参数")->end();
            return;
        }
        $appList = $config["appList"] ?? [];
        if (empty($appList)) {
            getHttpResponse()->withText("Fail: 没有可用的支付应用")->end();
            return;
        }
        $app = !empty($appId) ? ($appList[$appId] ?? reset($appList)) : reset($appList);
        $app = is_array($app) ? $app : [];
        if (empty($app)) {
            getHttpResponse()->withText("Fail: 未配置的支付应用")->end();
            return;
        }
        $appId = $app["appId"] ?? $appId;
        if (empty($appId)) {
            getHttpResponse()->withText("Fail: 缺少支付应用ID")->end();
            return;
        }
        //开发模式
        $dev = isset($app["dev"]) && $app["dev"] === true;
        //统一网关
        $gatewayUrl = $app["gatewayUrl"] ?? "https://openapi.alipay.com/gateway.do";
        //构造
        $alipayParams = new \Yurun\PaySDK\AlipayApp\Params\PublicParams;
        $alipayParams->appID = $appId;
        $alipayParams->appPrivateKey = $app["privateKey"];
        $alipayParams->appPublicKey = $app["publicKey"];
        $alipayParams->apiDomain = $gatewayUrl;
        //
        $sdk = new \Yurun\PaySDK\AlipayApp\SDK($alipayParams);
        try {
            $client = getClient();
            if ($sdk->verifyCallback($client->post)) {
                $tradeStatus = POST("trade_status");
                if ($tradeStatus === "TRADE_SUCCESS") {
                    //仅在交易成功时处理，但，请勿重复处理
                    $cashierId = POST("out_trade_no");
                    //订单号前缀
                    $outTradeNoPrefix = $app["outTradeNoPrefix"] ?? "";
                    //如果携带有前缀，需要去除前缀再使用
                    if (!empty($outTradeNoPrefix) && stripos($cashierId, $outTradeNoPrefix) === 0) {
                        $cashierId = substr($cashierId, strlen($outTradeNoPrefix));
                    }
                    $transactionId = POST('trade_no');
                    $buyerAccount = POST('buyer_logon_id');
                    $payedAmount = POST('buyer_pay_amount');
                    $payedAmount = is_numeric($payedAmount) && $payedAmount > 0 ? $payedAmount : 0;
                    $msg = CashierModel::payed($cashierId, $payedAmount, $transactionId, $buyerAccount, "alipay", $appId, json_encode($client->post, 256), $dev);
                    if ($msg->error !== 0) {
                        Log::writeToEnd(RUNTIME."/logs/alipay.txt", json_encode(["cashierId" => $cashierId, "message" => "未能处理付款通知"]));
                    }
                }
                getHttpResponse()->withText("success")->end();
            } else {
                Log::writeToEnd(RUNTIME."/logs/alipay.txt", "数据校验未通过");
                getHttpResponse()->withText("Fail")->end();
            }
        } catch (\Exception $exception) {
            Log::writeToEnd(RUNTIME."/logs/alipay.txt", $exception);
            getHttpResponse()->withText("Fail")->end();
        }
    }
}